package utils

import "sync"

type Stack[T any] struct {
	arr []T
}

func (s *Stack[T]) Push(v T) {
	if s.arr == nil {
		s.arr = make([]T, 0, 10)
	}
	s.arr = append(s.arr, v)
}

func (s *Stack[T]) Pop() (t T, ok bool) {
	l := s.Size()
	if l == 0 {
		return t, false
	}
	v := (s.arr)[l-1]
	s.arr = (s.arr)[:l-1]
	return v, true
}

func (s *Stack[T]) Size() int {
	return len(s.arr)
}

func (s *Stack[T]) IsEmpty() bool {
	return s.Size() == 0
}

type LockStack[T any] struct {
	s Stack[T]
	sync.Mutex
}

func (s *LockStack[T]) Push(v T) {
	s.Lock()
	defer s.Unlock()
	s.s.Push(v)
}

func (s *LockStack[T]) Pop() (t T, ok bool) {
	if s.s.IsEmpty() {
		return t, false
	}
	return s.s.Pop()
}

func (s *LockStack[T]) IsEmpty() bool {
	return s.s.IsEmpty()
}

func (s *LockStack[T]) Size() int {
	return s.s.Size()
}
